/* Copyright (c) 2004-2008, Andriy Nikolov
 * All rights reserved.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package org.processmining.analysis.email;

import org.processmining.analysis.*;
import org.processmining.framework.plugin.*;
import org.processmining.email.*;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.*;
import att.grappa.*;
import org.processmining.framework.util.*;
import cern.colt.matrix.*;
import java.io.FileWriter;
import org.processmining.framework.ui.*;
import java.io.*;
import java.text.*;

/**
 * <p> Produces a sociogram based on an imported e-mail log
 *
 * @author Andriy Nikolov
 * @version 1.0
 */
public class EMailSNAAnalysis extends JPanel implements AnalysisPlugin, SociogramProducer, Provider {
  Sociogram sociogram;
  SociogramTableModel sociogramTableModel;
  EMailLog log;
  boolean useThreadsOnly = false;
  BorderLayout borderLayout1 = new BorderLayout();
  BorderLayout borderLayout2 = new BorderLayout();
  JSplitPane jSplitPane1 = new JSplitPane();
  JScrollPane jScrollPaneSociogramTable = new JScrollPane();
  JScrollPane jScrollPaneSociogramTableInner = new JScrollPane();
  JPanel jSociogramTablePanel = new JPanel();
  JTable jTableSociogram = new JTable();
  JScrollPane jScrollPaneGraph = new JScrollPane();
  GrappaPanel grappaPanel;
  SociogramOptionsDialog sociogramOptionsDialog;

  public EMailSNAAnalysis() {
    super();
    try {
      jbInit();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public String getName() {
    return ("E-Mail SNA Analysis");
  }

  /**
   * accepts only EMailLog instances
   *
   * @return AnalysisInputItem[]
   */
  public AnalysisInputItem[] getInputItems() {
    AnalysisInputItem[] items = {
      new AnalysisInputItem("E-mail log") {
        public boolean accepts(ProvidedObject object) {
          Object[] o = object.getObjects();
          for(int i=0;i<o.length;i++)
            if(o[i] instanceof EMailLog)
              return true;

          return false;
        }
      }
    } ;
    return items;
  }

  public JComponent analyse(AnalysisInputItem[] inputs) {
    log = null;
    AnalysisInputItem inputItem;
    ProvidedObject[] pos;
    ProvidedObject po;
    Object[] os;
    Object o;

    inputItem = inputs[0];
    pos = inputItem.getProvidedObjects();
    po = pos[0];
    os = po.getObjects();

    for(int i=0;i<os.length;i++) {
      o = os[i];
      if(o instanceof EMailLog) {
        log = (EMailLog)o;
        break;
      }
    }

    if(log==null)
      return null;

    sociogramOptionsDialog = new SociogramOptionsDialog(MainUI.getFrames()[0], this, "Sociogram options", true);
    sociogramOptionsDialog.setLocationRelativeTo(this);
    sociogramOptionsDialog.validate();
    sociogramOptionsDialog.setVisible(true);

    if(!sociogramOptionsDialog.isOK())
      return null;

    sociogram = log.getNewSociogram(useThreadsOnly);
    sociogramTableModel = new SociogramTableModel(sociogram);
    jTableSociogram.setModel(sociogramTableModel);
    drawGraphPanel();
    jScrollPaneGraph.getViewport().add(grappaPanel);

    return this;
  }

  private void drawGraphPanel() {
    BufferedWriter bw;
    Graph graph;
    NumberFormat nf = NumberFormat.getInstance();
    File dotFile;

    EMailRecipient tmp;

    nf.setMinimumFractionDigits(3);
    nf.setMaximumFractionDigits(3);
    try {
      // create temporary DOT file
      dotFile = File.createTempFile("pmt", ".dot");
      bw = new BufferedWriter(new FileWriter(dotFile, false));
      bw.write("digraph G {ranksep=\".3\"; fontsize=\"8\"; remincross=true; margin=\"0.0,0.0\"; ");
      bw.write("fontname=\"Arial\";rankdir=\"LR\"; \n");
      bw.write("edge [arrowsize=\"0.5\",decorate=true,fontname=\"Arial\",fontsize=\"8\"];\n");
      bw.write("node [height=\".1\",width=\".2\",fontname=\"Arial\",fontsize=\"8\"];\n");

      for (int i = 0; i < sociogram.getEmployeesList().size(); i++) {
        tmp = (EMailRecipient)sociogram.getEmployeesList().get(i);
        bw.write("t" + i + " [shape=\"box\",label=\"" + tmp.getName() + "\"];\n");
      }

      for (int i = 0; i < sociogram.getEmployeesList().size(); i++) {
        for (int j = 0; j < sociogram.getEmployeesList().size(); j++) {
          double value = sociogram.getWeight(i, j);

          if (value > 0) {
            bw.write("t" + i + " -> t" + j + " [label=\"" + nf.format(value) + "\"];\n");
          }
        }
      }
      bw.write("}\n");
      bw.close();

      // execute dot and parse the output of dot to create a Graph
      System.out.println(dotFile.getAbsolutePath());
      graph = Dot.execute(dotFile.getAbsolutePath(), true);

      // adjust some settings
      graph.setEditable(true);
      graph.setMenuable(true);
      graph.setErrorWriter(new PrintWriter(System.err, true));

      // create the visual component and return it
      grappaPanel = new GrappaPanel(graph);
      grappaPanel.addGrappaListener(new GrappaAdapter());
      grappaPanel.setScaleToFit(true);

      return;
    } catch (Exception ex) {
      Message.add("Error while performing graph layout: " + ex.getMessage(), Message.ERROR);
      return;
    }
  }

  public String getHtmlDescription() {
    return "...";
  }

  public void jbInit() {
    this.setLayout(borderLayout1);
    jSplitPane1.setOrientation(JSplitPane.VERTICAL_SPLIT);
    jSplitPane1.setDividerLocation(100);
    this.add(jSplitPane1, java.awt.BorderLayout.CENTER);
    jScrollPaneSociogramTableInner.getViewport().add(jTableSociogram);
    jSociogramTablePanel.setLayout(borderLayout2);
    jSociogramTablePanel.add(jScrollPaneSociogramTableInner, java.awt.BorderLayout.CENTER);
    jScrollPaneSociogramTable.getViewport().add(jSociogramTablePanel);
    jSplitPane1.add(jScrollPaneSociogramTable, JSplitPane.TOP);
    jSplitPane1.add(jScrollPaneGraph, JSplitPane.BOTTOM);
  }

  public void setUseThreadsOnly(boolean value) {
    useThreadsOnly = value;
  }

  public ProvidedObject[] getProvidedObjects()
  {
    return (new ProvidedObject[] {
      new ProvidedObject("Sociogram", new Object[] {
        sociogram
      })
    });
  }

}
